package com.easylinkin.linkappapi.safe.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.easylinkin.linkappapi.common.service.CommonService;
import com.easylinkin.linkappapi.common.utils.excel.ExcelConstant;
import com.easylinkin.linkappapi.common.utils.excel.ExcelTools;
import com.easylinkin.linkappapi.common.utils.io.OutputStreamUtil;
import com.easylinkin.linkappapi.safe.dao.DangerousDangerRefMapper;
import com.easylinkin.linkappapi.safe.dao.DangerousFileMapper;
import com.easylinkin.linkappapi.safe.dao.DangerousInfoMapper;
import com.easylinkin.linkappapi.safe.dao.DangerousProcessMapper;
import com.easylinkin.linkappapi.safe.dto.DangerousInfoDto;
import com.easylinkin.linkappapi.safe.entity.*;
import com.easylinkin.linkappapi.safe.entity.vo.DangerousInfoExcelVo;
import com.easylinkin.linkappapi.safe.entity.vo.DangerousInfoVo;
import com.easylinkin.linkappapi.safe.service.DangerousInfoService;
import com.easylinkin.linkappapi.safe.service.HiddenActionRecordsService;
import com.easylinkin.linkappapi.safe.service.HiddenDangerService;
import com.easylinkin.linkappapi.security.context.LinkappUserContextProducer;
import com.easylinkin.linkappapi.security.entity.LinkappUser;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import site.morn.rest.RestBuilders;
import site.morn.rest.RestMessage;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;

/**
 * DangerousInfo表服务实现类
 *
 * @author zhengwen
 * @date 2022/08/16
 */
@Slf4j
@Service("appDangerousInfoService")
public class DangerousInfoServiceImpl extends ServiceImpl
        <DangerousInfoMapper, DangerousInfo> implements DangerousInfoService {
    @Resource
    private CommonService commonService;
    @Resource
    private LinkappUserContextProducer linkappUserContextProducer;

    @Resource
    private DangerousProcessMapper dangerousProcessMapper;

    @Resource
    private DangerousFileMapper dangerousFileMapper;

    @Resource
    private DangerousDangerRefMapper dangerousDangerRefMapper;

    @Resource
    private HiddenDangerService hiddenDangerService;

    @Resource
    private HiddenActionRecordsService hiddenActionRecordsService;

    @Override
    public boolean saveOne(DangerousInfo appDangerousInfo) {
        commonService.setCreateAndModifyInfo(appDangerousInfo);
        // appDangerousInfo.setTenantId(linkappUserContextProducer.getNotNullCurrent().getTenantId());
        validParamRequired(appDangerousInfo);
        validRepeat(appDangerousInfo);
        validParamFormat(appDangerousInfo);
        return save(appDangerousInfo);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateOne(DangerousInfo appDangerousInfo) {
        Assert.notNull(appDangerousInfo.getId(), "id不能为空");
        commonService.setModifyInfo(appDangerousInfo);
        //appDangerousInfo.setTenantId(linkappUserContextProducer.getNotNullCurrent().getTenantId());
        validRepeat(appDangerousInfo);
        validParamFormat(appDangerousInfo);
        return updateById(appDangerousInfo);
    }

    @Override
    public IPage<DangerousInfo> selectPage(Page page, DangerousInfo appDangerousInfo) {
        //appDangerousInfo.setTenantId(linkappUserContextProducer.getNotNullCurrent().getTenantId());
        return baseMapper.selectPage(page, appDangerousInfo);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteByIds(List<Long> idList) {
        return removeByIds(idList);
    }

    @Override
    public void export(DangerousInfoVo dangerousInfoVo, HttpServletRequest request, HttpServletResponse
            response) {

        IPage<DangerousInfoDto> page = selectDtoPage(new Page(0, -1), dangerousInfoVo);
        List<DangerousInfoDto> records = page.getRecords();
        List<DangerousInfoExcelVo> appDangerousInfoVos = new ArrayList<>();
        for (DangerousInfoDto expert : records) {
            appDangerousInfoVos.add(new DangerousInfoExcelVo(expert));
        }

        String keyValue = "类别:typeName,危大工程名称:name,是否超危:superDangerousName,计划时间:planTime,实际开始时间:actualStartTimeStr,实际结束时间:actualEndTimeStr,工区责任人:workAreaResponsible,分包责任人:subAreaResponsible,责任分包单位:subResponsibleOrg,方案状态:programStateName,施工状态:constructionStateName";
        String title = "危大工程导出数据";
        String fileName = title + ".xls";
        try {
            OutputStream outputStream = OutputStreamUtil
                    .getOutputStream(request, response, fileName);
            ExcelTools.exportExcel(outputStream, keyValue, appDangerousInfoVos, ExcelConstant.XLS, title);
            response.flushBuffer();
            outputStream.close();
        } catch (IOException e) {
            log.error("excel导出失败", e);
            throw new RuntimeException("excel导出失败！IOException异常" + e.getMessage());
        } catch (Exception e) {
            log.error("excel导出失败", e);
            throw new RuntimeException("excel导出失败！" + e.getMessage());
        }
    }

    @Override
    public RestMessage saveDangerousInfo(DangerousInfoVo dangerousInfoVo) {
        //参数校验
        cn.hutool.core.lang.Assert.isTrue(StringUtils.isNotBlank(dangerousInfoVo.getName()), "危大工程名称不能为空");
        cn.hutool.core.lang.Assert.isTrue(StringUtils.isNotBlank(dangerousInfoVo.getDescribeStr()), "危大工程概况不能为空");
        cn.hutool.core.lang.Assert.isFalse(dangerousInfoVo.getSuperDangerous() == null, "危大工程是否超危不能为空");
        cn.hutool.core.lang.Assert.isFalse(dangerousInfoVo.getTypeId() == null, "危大工程类别不能为空");
        cn.hutool.core.lang.Assert.isFalse(dangerousInfoVo.getTypeDescribeId() == null, "危大工程类别不能为空");
        cn.hutool.core.lang.Assert.isTrue(StringUtils.isNotBlank(dangerousInfoVo.getWorkAreaResponsible()), "工区责任人不能为空");
        cn.hutool.core.lang.Assert.isTrue(StringUtils.isNotBlank(dangerousInfoVo.getSubAreaResponsible()), "分包责任人不能为空");
        cn.hutool.core.lang.Assert.isTrue(StringUtils.isNotBlank(dangerousInfoVo.getSubResponsibleOrg()), "责任分包单位不能为空");

        LinkappUser linkappUser = linkappUserContextProducer.getNotNullCurrent();

        //过程资料
        Map<Integer, DangerousProcess> processMap = new HashMap<>();
        List<DangerousProcess> processList = dangerousInfoVo.getProcessList();
        if (CollectionUtil.isNotEmpty(processList)) {
            processMap = processList.stream().collect(Collectors.toMap(DangerousProcess::getStepNo, p -> p));
        }

        DangerousInfo dangerousInfo = saveOrUpdateDangerousInfo(dangerousInfoVo, linkappUser, processMap);

        //过程与资料保存
        List<DangerousFile> processFileList = dangerousInfoVo.getProcessFileList();
        Map<Integer, List<DangerousFile>> processFileMap = new HashMap<>();
        if (CollectionUtil.isNotEmpty(processFileList)) {
            processFileMap = processFileList.stream().collect(Collectors.groupingBy(DangerousFile::getStepNo));
        }
        //保存过程与资料
        saveOrUpdateProcessInfo(dangerousInfo, processMap, processFileMap, linkappUser);

        //保存危大过程过程检查，20220822增加保存逻辑
        List<HiddenDanger> hiddenDangerList = dangerousInfoVo.getHiddenDangerList();
        if (CollectionUtil.isNotEmpty(hiddenDangerList)){
            hiddenDangerList.stream().forEach(d->{
                String hiddenDangerId = d.getId();
                if (StringUtils.isBlank(hiddenDangerId)){
                    //新增  //保存隐患
                    hiddenDangerService.saveOne(d);
                    //添加查询记录
                    HiddenActionRecords hiddenActionRecords = new HiddenActionRecords();
                    hiddenActionRecords.setActionType(1);
                    hiddenActionRecords.setLinkId(d.getId());
                    hiddenActionRecordsService.insert(hiddenActionRecords);
                }
            });
        }

        //那边数据已经保存了，这边做关联关系处理
        saveDangerousDangerRef(dangerousInfo, linkappUser, hiddenDangerList);

        return RestBuilders.successBuilder().build();
    }

    @Override
    public IPage<DangerousInfoDto> selectDtoPage(Page page, DangerousInfoVo dangerousInfoVo) {
        dangerousInfoVo.setTenantId(linkappUserContextProducer.getNotNullCurrent().getTenantId());
        IPage<DangerousInfoDto> iPage =  baseMapper.selectDtoPage(page, dangerousInfoVo);
        return iPage;
    }

    @Override
    public RestMessage selectOneDto(Long id) {
        cn.hutool.core.lang.Assert.isFalse(id == null,"id为空");
        DangerousInfoDto dto = this.baseMapper.selectOneDtoById(id);

        return RestBuilders.successBuilder().data(dto).build();
    }

    @Override
    public RestMessage batchDelete(List<Long> idList) {
        if (CollectionUtil.isNotEmpty(idList)) {
            QueryWrapper<DangerousDangerRef> qw = new QueryWrapper<>();
            qw.eq("delete_state",1);
            qw.in("dangerous_id",idList);
            List<DangerousDangerRef> refLs = dangerousDangerRefMapper.selectList(qw);
            if (CollectionUtil.isNotEmpty(refLs)) {
                return RestBuilders.errorBuilder().message("选择的数据与检查台账数据有关联，请检查先删除检查台账数据").build();
            }
            this.baseMapper.deleteBatchIds(idList);
        }
        return RestBuilders.successBuilder().build();
    }

    /**
     * 保存危大工程与安全隐患关系
     * @param dangerousInfo 危大工程信息
     * @param linkappUser 当前登录用户
     * @param hiddenDangerList 安全隐患信息list
     */
    private void saveDangerousDangerRef(DangerousInfo dangerousInfo, LinkappUser linkappUser, List<HiddenDanger> hiddenDangerList) {
        if (CollectionUtil.isNotEmpty(hiddenDangerList)) {
            hiddenDangerList.stream().forEach(h -> {
                DangerousDangerRef ddRef = new DangerousDangerRef();
                ddRef.setDangerousId(dangerousInfo.getId());
                ddRef.setDangerId(h.getId());
                ddRef.setDeleteState(1);
                ddRef.setCreator(String.valueOf(linkappUser.getId()));
                ddRef.setCreateTime(DateUtil.date());
                //先查询
                QueryWrapper<DangerousDangerRef> queryWrapper = new QueryWrapper<>();
                queryWrapper.eq("dangerous_id", dangerousInfo.getId());
                queryWrapper.eq("danger_id", h.getId());
                queryWrapper.eq("delete_state", 1);
                DangerousDangerRef dbddRef = dangerousDangerRefMapper.selectOne(queryWrapper);
                if (dbddRef == null) {
                    dangerousDangerRefMapper.insert(ddRef);
                }

            });
        }

    }

    /**
     * 保存活更新过程信息
     * @param dangerousInfo 危大工程信息
     * @param processMap 过程map
     * @param processFileMap 文件map
     * @param linkappUser 当前登录用户
     */
    private void saveOrUpdateProcessInfo(DangerousInfo dangerousInfo, Map<Integer, DangerousProcess> processMap, Map<Integer, List<DangerousFile>> processFileMap, LinkappUser linkappUser) {
        //循环
        processMap.entrySet().stream().forEach(p -> {
            Integer stepNo = p.getKey();
            DangerousProcess dangerousProcess = p.getValue();
            if (dangerousProcess != null) {
                Long processId = null;
                QueryWrapper<DangerousProcess> processQueryWrapper = new QueryWrapper<>();
                processQueryWrapper.eq("dangerous_id", dangerousInfo.getId());
                processQueryWrapper.eq("step_no", stepNo);
                processQueryWrapper.eq("delete_state", 1);
                DangerousProcess dbProcess = dangerousProcessMapper.selectOne(processQueryWrapper);
                if (dbProcess == null) {
                    //参数补充
                    dangerousProcess.setDangerousId(dangerousInfo.getId());
                    dangerousProcess.setCreator(String.valueOf(linkappUser.getId()));
                    dangerousProcess.setCreateTime(DateUtil.date());
                    dangerousProcess.setModifier(dangerousProcess.getCreator());
                    dangerousProcess.setModifyTime(dangerousProcess.getCreateTime());
                    dangerousProcess.setDeleteState(1);
                    dangerousProcessMapper.insert(dangerousProcess);
                    processId = dangerousProcess.getId();
                } else {
                    BeanUtil.copyProperties(dangerousProcess, dbProcess, CopyOptions.create().setIgnoreNullValue(true));
                    dbProcess.setModifier(String.valueOf(linkappUser.getId()));
                    dbProcess.setModifyTime(DateUtil.date());
                    dangerousProcessMapper.updateById(dbProcess);
                    processId = dbProcess.getId();
                }
                //保存资料，不好判断资料是否存在，先直接删除，在保存
                QueryWrapper processFileQueryWrapper = new QueryWrapper<>();
                processFileQueryWrapper.eq("dangerous_id", dangerousInfo.getId());
                processFileQueryWrapper.eq("process_id", processId);
                processFileQueryWrapper.eq("step_no", stepNo);
                processFileQueryWrapper.eq("delete_state", 1);
                dangerousFileMapper.delete(processFileQueryWrapper);

                //再保存
                List<DangerousFile> dangerousFileLs = processFileMap.get(stepNo);
                if (CollectionUtil.isNotEmpty(dangerousFileLs)) {
                    Long finalProcessId = processId;
                    dangerousFileLs.stream().forEach(f -> {
                        f.setDangerousId(dangerousInfo.getId());
                        f.setProcessId(finalProcessId);
                        f.setCreator(String.valueOf(linkappUser.getId()));
                        f.setCreateTime(DateUtil.date());
                        f.setDeleteState(1);
                        dangerousFileMapper.insert(f);
                    });
                }

            }
        });
    }

    /**
     * 保存或更新危大工程信息
     * @param dangerousInfoVo 危大工程vo
     * @param linkappUser 当前登录用户
     * @param processMap 过程map
     * @return 危大工程信息
     */
    private DangerousInfo saveOrUpdateDangerousInfo(DangerousInfoVo dangerousInfoVo, LinkappUser linkappUser, Map<Integer, DangerousProcess> processMap) {
        DangerousInfo dangerousInfo = new DangerousInfo();
        BeanUtil.copyProperties(dangerousInfoVo, dangerousInfo, CopyOptions.create().setIgnoreNullValue(true));

        //方案状态处理   已完成=专项施工方案状态为完成,  未完成:专项施工方案状态为未完成
        DangerousProcess process = processMap.get(1);
        if (process != null) {
            Integer prcessState = process.getProcessState();
            if (prcessState != null) {
                dangerousInfo.setProgramState(prcessState);
            }
        }

        //施工状态处理，1未开工，2在施，3完工
        //  未开工=实际开始和实际结束为空时,  在施=实际开始有数据时,且此日期早于等于今天,  完工=实际开始实际结束有数据,且实际开始早于实际结束,实际结束早于等于今天
        Date now = DateUtil.date();
        Date planStartTime = dangerousInfoVo.getPlanStartTime();
        Date planEndTime = dangerousInfoVo.getPlanEndTime();
        dangerousInfo.setPlanStartTime(planStartTime);
        dangerousInfo.setPlanEndTime(planEndTime);
        /*if (planStartTime != null){
            dangerousInfo.setPlanStartTime(DateUtil.beginOfDay(planStartTime));
        }
        if (planEndTime != null){
            dangerousInfo.setPlanEndTime(DateUtil.endOfDay(planEndTime).offset(DateField.MILLISECOND,-999));
        }*/

        Date actualStartTime = dangerousInfoVo.getActualStartTime();
        Date actualEndTime = dangerousInfoVo.getActualEndTime();
        dangerousInfo.setActualStartTime(actualStartTime);
        dangerousInfo.setActualEndTime(actualEndTime);

        if (actualStartTime == null){
            dangerousInfo.setConstructionState(1);
        }else {
            if (actualStartTime.after(now)){
                dangerousInfo.setConstructionState(1);
            }else {
                dangerousInfo.setConstructionState(2);
            }
        }
        if (actualEndTime == null){
            dangerousInfo.setConstructionState(2);
        }else {
            if (actualEndTime.after(now)){
                dangerousInfo.setConstructionState(2);
            }else {
                dangerousInfo.setConstructionState(3);
            }
        }

        if (actualStartTime != null && actualEndTime != null) {
            if (actualStartTime.before(actualEndTime) && actualEndTime.before(now)){
                dangerousInfo.setConstructionState(3);
            }else {
                dangerousInfo.setConstructionState(2);
            }
        }else {
            dangerousInfo.setConstructionState(1);
        }

        if (actualStartTime != null && actualStartTime.before(now) && (actualEndTime == null || actualEndTime.after(now))) {
            dangerousInfo.setConstructionState(2);
        }

        Long id = dangerousInfoVo.getId();
        if (id == null) {
            //补充信息
            dangerousInfo.setCreateTime(DateUtil.date());
            dangerousInfo.setModifyTime(dangerousInfo.getCreateTime());
            dangerousInfo.setTenantId(linkappUser.getTenantId());
            dangerousInfo.setCreator(String.valueOf(linkappUser.getId()));
            dangerousInfo.setModifier(dangerousInfo.getCreator());
            dangerousInfo.setProgramState(1);
            dangerousInfo.setDeleteState(1);
            this.baseMapper.insert(dangerousInfo);
        } else {
            dangerousInfo.setTenantId(linkappUser.getTenantId());
            //dangerousInfo.setId(id);
            dangerousInfo.setModifier(dangerousInfo.getCreator());
            dangerousInfo.setModifyTime(DateUtil.date());
            //this.baseMapper.updateById(dangerousInfo);
            UpdateWrapper<DangerousInfo> updateWrapper = new UpdateWrapper();
            updateWrapper.eq("id",id);
            //updateWrapper.eq("delete_state",dangerousInfo.getDeleteState());
            updateWrapper.set("plan_start_time",planStartTime);
            updateWrapper.set("plan_end_time",planEndTime);
            updateWrapper.set("actual_start_time",dangerousInfo.getActualStartTime());
            updateWrapper.set("actual_end_time",dangerousInfo.getActualEndTime());
            this.baseMapper.update(dangerousInfo,updateWrapper);
        }
        return dangerousInfo;
    }

    @Override
    public DangerousInfo getOneById(Serializable id) {
        return baseMapper.getOneById(id);
    }

    /**
     * 校验重复
     */
    private void validRepeat(DangerousInfo appDangerousInfo) {
        /* QueryWrapper<DangerousInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("name", appDangerousInfo.getName());
        queryWrapper.eq("tenant_id", linkappUserContextProducer.getNotNullCurrent().getTenantId());
        List<DangerousInfo> list = baseMapper.selectList(queryWrapper);
        if (list.size() == 0) {
            return;
        }
        if (list.size() > 1) {
            throw new BusinessException("名称有重复");
        }
        if (ObjectUtils.isEmpty(appDangerousInfo.getId())) {
            throw new BusinessException("名称已存在");
        }
        if (!appDangerousInfo.getId().equals(list.get(0).getId())) {
            throw new BusinessException("名称已存在");
        }
                    */

    }


    /**
     * 校验参数必填
     */
    private void validParamRequired(DangerousInfo appDangerousInfo) {
        //Assert.notNull(appDangerousInfo, "参数为空");
        //Assert.isTrue(StringUtils.isNotBlank(appDangerousInfo.getName()), "名称为空");
    }

    /**
     * 校验参数格式
     */
    private void validParamFormat(DangerousInfo appDangerousInfo) {
        //Assert.isTrue(appDangerousInfo.getName() == null || appDangerousInfo.getName().length() <= 50,
        //        "名称超长");
    }
}

